package com.orion.config;

import org.springframework.http.HttpMethod;
import org.springframework.lang.Nullable;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.*;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 参考 UsernamePasswordAuthenticationFilter ，它是默认的用户名密码登录的filter
 *
 * @author Administrator
 * @date 2021/9/13
 */
public class VerifyCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    public static final String SPRING_SECURITY_FORM_VERIFYCODE_KEY = "verifyCode";

    private String verifyCodeParameter = SPRING_SECURITY_FORM_VERIFYCODE_KEY;

    private boolean postOnly = true;

    protected VerifyCodeAuthenticationFilter() {
        super(new AntPathRequestMatcher("/haha", "POST"));
    }


    /**
     * @attemptAuthentication 方法主要是搜集参数（username、password）
     * ，封装为验证请求（UsernamePasswordAuthenticationToken），
     * 然后调用AuthenticationManager 进行身份认证,
     * AuthenticationManager再交给provider去具体认证
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        if (postOnly && !request.getMethod().equals(HttpMethod.POST.name())) {
            throw new AuthenticationServiceException(
                    "Authentication method not supported: " + request.getMethod());
        }

        String verifyCode = obtainVerifyCode(request);
        if (verifyCode == null) {
            verifyCode = "";
        }
        verifyCode = verifyCode.trim();

        VerifyCodeAuthenticationToken verifyCodeAuthenticationToken = new VerifyCodeAuthenticationToken(verifyCode);
        this.setDetails(request, verifyCodeAuthenticationToken);

        AuthenticationManager authenticationManager = this.getAuthenticationManager();

        return authenticationManager.authenticate(verifyCodeAuthenticationToken);

    }

    @Nullable
    private String obtainVerifyCode(HttpServletRequest request) {
        return request.getParameter(verifyCodeParameter);
    }


    private void setDetails(HttpServletRequest request,
                              VerifyCodeAuthenticationToken authRequest) {
        authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
    }
}
